# -*- coding: utf-8 -*-
from pprint import pprint

class Analyzer(object):
    pass

    def __init__(self, size, modify, reduce):
        self.results = []
        self.circuit = None
        self.index_traversing = None
        self.primary_IN_traversing = None
        self.amount_paths_traversed = None
        self.size = size
        self.modify = modify
        self.reduce = reduce
        
    
    def feed(self, circuit):
        """ feeds analyzer with new circuit.
            it is useful for massive analysis """
        self.circuit = circuit

        
    def process(self):
        """ feeds analyzer with new circuit.
            it is useful for massive analysis 
            There are three kinds of connections:
            gate - gate # typical gates connection
            None - gate # primary input
            gate - None # primary output """

        # name primary INs and OUTs
        for i, primary_IN_path in enumerate(self.circuit.inputList):
            primary_IN_path.name = i
            self.circuit.outputList[i].name = i
        
        # traverse all primary IN gates until primary OUT's found    
        for i, IN_connection in enumerate(self.circuit.inputList):
            #print 'processing next primary input %s' % (i)
            self.index_traversing = i
            self.primary_IN_traversing = IN_connection
            self.traverse(IN_connection.output)
            self.amount_paths_traversed = len(self.results)
        #print 'Processing completed with %i paths measured' % (self.amount_paths_traversed)
        #pprint(self.results)
            
            
    def traverse(self, gate, delay = 0):
        """ traverse circuit; it takes all primary INs and goes 
            through all paths until it reaches all primary OUTs
            method affects internally self.results[], where 
            traverse results can be found """
            
        delay += 1
        for path in gate.outputList:
            if path.output:
                self.traverse(path.output, delay)
            else:
                self.results.append({'index':self.index_traversing,
                                    'primary_in':self.primary_IN_traversing.name,
                                    'primary_out':path.name,
                                    'delay':delay })
                
                #print 'In:%(primary_IN)s Out:%(primary_OUT)s delay:%(delay)i' % \
                #    {'index':self.index_traversing, 'primary_IN':self.primary_IN_traversing.name, \
                #     'primary_OUT':path.name, 'delay':delay}
            

    def createPlot(self):
        """ call gnuplot to create fancy plots :) """

        try:
            import Gnuplot#, Gnuplot.funcutils
        except:
            print 'Sorry, you don\'t have Gnuplot Python connector package installed'
            return
        GNUPLOT_DEBUG = 0
        g = Gnuplot.Gnuplot(debug=GNUPLOT_DEBUG)
        g('set data style boxes')
        x_axis_data = []
        
        ##########################################
        # path delay sorted
        for obj in self.results:
            x_axis_data.append(obj['delay'])
        x_axis_data.sort()
        ##########################################
        g.plot(x_axis_data)
        g.xlabel('Paths')
        g.ylabel('Path delay units (sorted)')
        g.hardcopy('wykresy/batcher_sorted_%s_x%s_reduce=%s_modify=%s.eps' % (self.amount_paths_traversed, self.size, self.reduce, self.modify), enhanced=1, color=0, mode='eps', solid=1)
        g.hardcopy('wykresy/batcher_sorted_%s_x%s_reduce=%s_modify=%s.png' % (self.amount_paths_traversed, self.size, self.reduce, self.modify), terminal='png', color=0)
        raw_input()
        
        x_axis_data = []
        ##########################################
        # path alignment in matrix
        for i, obj in enumerate(self.results):
            x_axis_data.append((i, obj['delay']))
        ###########################################

        
        g.plot(x_axis_data)
        g.xlabel('Paths')
        g.ylabel('Path delay units')

        g.hardcopy('wykresy/batcher_%s_x%s_reduce=%s_modify=%s.eps' % (self.amount_paths_traversed, self.size, self.reduce, self.modify), enhanced=1, color=0, mode='eps', solid=1)
        g.hardcopy('wykresy/batcher_%s_x%s_reduce=%s_modify=%s.png' % (self.amount_paths_traversed, self.size, self.reduce, self.modify), terminal='png', color=0)
        
        #g.hardcopy('wykresy/batcher_%s_%sx%s.png' % (self.amount_paths_traversed, self.bits, self.size), terminal='png', color=0)


    def makeStatistics(self):

        ##########################################
        # path delay sorted
        sum = 0
        x_axis_data = []
        for obj in self.results:
            x_axis_data.append(obj['delay'])
            sum += obj['delay']
        x_axis_data.sort()
        
        average = sum/len(x_axis_data)
        longest = x_axis_data.pop()
        shortest = x_axis_data[0]
        print '========================== SUMMARY ================================'
        print 'PATH DELAY SUM: %s' % (sum)
        print 'SHORTEST PATH: %s' % (shortest)
        print 'PATH AVERAGE: %s' % (average)
        print 'LONGEST PATH: %s' % (longest)
        print 'AMOUNT PATHS MEASURED: %s' % (self.amount_paths_traversed)
        print shortest, ',', average, ',', longest, ',', self.amount_paths_traversed
        return '%s, %s, %s, %s' % (shortest, average, longest, self.amount_paths_traversed)


if __name__ == '__main__':
    from generator import Generator
    from comparators import BitCmpCircuit
    import sys
    gen = Generator()

    wrong_params = False         
    if '-size' in sys.argv:
        size_index = sys.argv.index('-size')
        try:
            SIZE = int(sys.argv[size_index + 1])
        except:
            print 'No circuit size number given!\n'
            sys.exit(2)
    else:
        wrong_params = True
        
    if '-modify' in sys.argv:
        size_index = sys.argv.index('-modify')
        try:
            MODIFY = int(sys.argv[size_index + 1])
        except:
            print 'No modify status given!\n'
            sys.exit(2)
    else:
        wrong_params = True

    if '-reduce' in sys.argv:
        size_index = sys.argv.index('-reduce')
        try:
            REDUCE = int(sys.argv[size_index + 1])
        except:
            print 'No reduce status given!\n'
            sys.exit(2)
    else:
        wrong_params = True

    if wrong_params:
        print 'Wrong params given! try:\n%s -size n -modify 0/1 -reduce 0/1\n' % (sys.argv[0])
        sys.exit(2)        

    #circuit_data = gen.generateOddEvenSort(BITS,SIZE,BitCmpCircuit)
    circuit_data = gen.generateOddEvenSort(SIZE,BitCmpCircuit,MODIFY,REDUCE)
    #circut = gen.generateOddEvenSort(10,BitCmpCircuit,True,True)
    #circuit_data = gen.generateOddEvenMerge(BITS, SIZE, DiffComparatorCircuit)
    print circuit_data
    analyzer = Analyzer(size=SIZE, modify=MODIFY, reduce=REDUCE)
    analyzer.feed(circuit_data)
    analyzer.process()
    #analyzer.createPlot()
    analyzer.makeStatistics()

